package com.liao.badminton.code.util;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import okhttp3.*;
import org.apache.commons.codec.Charsets;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

public final class HttpUtil {
	public static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);
	private static final MediaType CONTENT_TYPE_FORM = MediaType
			.parse("application/x-www-form-urlencoded;charset=UTF-8");
	private static final String DEFAULT_USER_AGENT = "MALL-SERVER";

	private static final int okHttpReadTimeout = 60;
	private static final int connectTimeout = 60;
	private static final int writeTimeout = 120;
	// 最大连接数
	private static final int MAX_CONNECTION = 100;
	// 每个route能使用的最大连接数，一般和MAX_CONNECTION取值一样
	private static final int MAX_CONCURRENT_CONNECTIONS = 100;
	// 建立连接的超时时间，单位毫秒
	private static final int CONNECTION_TIME_OUT = 1000 * 60;
	// 请求超时时间，单位毫秒
	private static final int REQUEST_TIME_OUT = 1000 * 120;
	private static HttpClient httpClient;

	private HttpUtil() {
	}

	// 请求配置，可以复用
	private static RequestConfig requestConfig;

	static {
		SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(REQUEST_TIME_OUT).setSoKeepAlive(true)
				.setTcpNoDelay(true).build();

		requestConfig = RequestConfig.custom().setSocketTimeout(REQUEST_TIME_OUT).setConnectTimeout(CONNECTION_TIME_OUT)
				.build();
		/**
		 * 每个默认的 ClientConnectionPoolManager 实现将给每个route创建不超过2个并发连接，最多20个连接总数。
		 */
		PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
		connManager.setMaxTotal(MAX_CONNECTION);
		connManager.setDefaultMaxPerRoute(MAX_CONCURRENT_CONNECTIONS);
		connManager.setDefaultSocketConfig(socketConfig);

		httpClient = HttpClients.custom().setConnectionManager(connManager).build();
	}

	public static final String get(String url) {
		String result = "";
		HttpGet method = new HttpGet(url);
		method.addHeader("User-Agent", DEFAULT_USER_AGENT);
		method.addHeader("Content-Type", CONTENT_TYPE_FORM.toString());
		try {
			HttpResponse response = httpClient.execute(method);
			HttpEntity resEntity = response.getEntity();
			result = EntityUtils.toString(resEntity);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			method.releaseConnection();
		}
		return result;
	}

	/**
	 * post请求，不带请求首部
	 * 
	 * @param url
	 * @param paramMap
	 * @return
	 * @throws Exception
	 */
	public static String post(String url, Map<String, String> paramMap) throws Exception {
		Map<String, String> headers = new HashMap<>();
		headers.put("User-Agent", DEFAULT_USER_AGENT);
		headers.put("Content-Type", CONTENT_TYPE_FORM.toString());
		return post(url, paramMap, headers);
	}

	/**
	 * post请求
	 * 
	 * @param url
	 * @param paramMap
	 * @param headers
	 * @return
	 * @throws Exception
	 */
	public static String post(String url, Map<String, String> paramMap, Map<String, String> headers) throws Exception {
		URIBuilder uriBuilder = new URIBuilder(url);
		if (paramMap != null) {
			// 添加请求参数
			for (Entry<String, String> entry : paramMap.entrySet()) {
				uriBuilder.addParameter(entry.getKey(), entry.getValue());
			}
		}
		HttpPost httpPost = new HttpPost(uriBuilder.build());
		if (headers != null) {
			// 添加请求首部
			for (Entry<String, String> entry : headers.entrySet()) {
				httpPost.addHeader(entry.getKey(), entry.getValue());
			}
		}

		httpPost.setConfig(requestConfig);
		// 执行请求
		HttpResponse response = httpClient.execute(httpPost);
		return EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
	}

	public static String postObject(String url, Map<String, Object> paramMap, Map<String, String> headers) throws Exception {
		URIBuilder uriBuilder = new URIBuilder(url);

		HttpPost httpPost = new HttpPost(uriBuilder.build());
		httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
		if (headers != null) {
			// 添加请求首部
			for (Entry<String, String> entry : headers.entrySet()) {
				httpPost.addHeader(entry.getKey(), entry.getValue());
			}
		}
		httpPost.setConfig(requestConfig);
		if (paramMap != null) {
			// 添加请求参数
//			SerializableEntity entity = new SerializableEntity(paramMap);
			StringEntity entity = new StringEntity(JSON.toJSONString(paramMap), "UTF-8");
			httpPost.setEntity(entity);
		}
		// 执行请求
		HttpResponse response = httpClient.execute(httpPost);
		return EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
	}

	public static okhttp3.OkHttpClient okHttpClient(Interceptor interceptor) {
		okhttp3.OkHttpClient.Builder builder = new okhttp3.OkHttpClient.Builder()
				.readTimeout(okHttpReadTimeout, TimeUnit.SECONDS).connectTimeout(connectTimeout, TimeUnit.SECONDS)
				.writeTimeout(writeTimeout, TimeUnit.SECONDS).connectionPool(new ConnectionPool());
		if (interceptor != null) {
			builder.addInterceptor(interceptor);
		}
		return builder.build();
	}

	public static String post(String url, String params) {
		RequestBody body = RequestBody.create(CONTENT_TYPE_FORM, params);
		Request request = new Request.Builder().url(url).post(body).build();
		return exec(request);
	}

	private static String exec(okhttp3.Request request) {
		try {
			okhttp3.Response response = okHttpClient(null).newCall(request).execute();
			if (!response.isSuccessful()) {
				throw new RuntimeException("Unexpected code " + response);
			}
			return response.body().string();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public static String postSSL(String url, String data, String certPath, String certPass) {
		try {
			KeyStore clientStore = KeyStore.getInstance("PKCS12");
			// 读取本机存放的PKCS12证书文件
			FileInputStream instream = new FileInputStream(certPath);
			try {
				// 指定PKCS12的密码(商户ID)
				clientStore.load(instream, certPass.toCharArray());
			} finally {
				instream.close();
			}
			SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(clientStore, certPass.toCharArray()).build();
			// 指定TLS版本
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" },
					null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
			// 设置httpclient的SSLSocketFactory
			CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			try {
				HttpPost httpost = new HttpPost(url); // 设置响应头信息
				httpost.addHeader("Connection", "keep-alive");
				httpost.addHeader("Accept", "*/*");
				httpost.addHeader("Content-Type", CONTENT_TYPE_FORM.toString());
				httpost.addHeader("X-Requested-With", "XMLHttpRequest");
				httpost.addHeader("Cache-Control", "max-age=0");
				httpost.addHeader("User-Agent", DEFAULT_USER_AGENT);
				httpost.setEntity(new StringEntity(data, "UTF-8"));
				CloseableHttpResponse response = httpclient.execute(httpost);
				try {
					HttpEntity entity = response.getEntity();
					String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
					EntityUtils.consume(entity);
					return jsonStr;
				} finally {
					response.close();
				}
			} finally {
				httpclient.close();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
